home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Pascal / Book Demos in Pascal / KeyConfig / KeyConfig.p < prev    next >
Text File  |  1995-04-10  |  10KB  |  377 lines

  1.  
  2. (* KeyConfig *)
  3.  
  4. (* }
  5. {By Ingemar Ragnemalm 1995}
  6. {This program shows a modal dialog box, in which you can select eight keys,}
  7. {supposedly fr keyboard control for a game, plus a three-button set of radio}
  8. {buttons and a checkbox. It also shows the key codes found for each key.}
  9. {}
  10. {You should study this program when making your own key configuration dialogs.}
  11. {The most important message is that you should get the key codes through events,}
  12. {not assume that everybody has the same key configuration as you have.}
  13. {*)
  14.  
  15. program KeyConfig;
  16.  
  17.     uses
  18. {$ifc UNDEFINED THINK_PASCAL}
  19.         Types, QuickDraw, Events, Windows, Dialogs, Fonts, DiskInit, TextEdit, Traps,{}
  20.         Memory, SegLoad, Scrap, ToolUtils, OSUtils, Menus, Resources, StandardFile, {}
  21.         GestaltEqu, Files, Errors, Packages, OSEvents, 
  22. {$endc}
  23.         Preferences;
  24.  
  25.  
  26. (* Prefs record *)
  27.  
  28.     type
  29.         PrefsRec = record
  30.                 keyCodes: array[0..7] of char;    (* Key codes *)
  31.                 keyChars: array[0..7] of char;    (* ASCII values *)
  32.                 myRadio: Integer;
  33.                 myCheckBox: Boolean;
  34.             end;
  35.  
  36.         PrefsPtr = ^PrefsRec;
  37.         PrefsHnd = ^PrefsPtr;
  38.  
  39.  
  40.     var
  41.         gPrefs: PrefsHnd;
  42.  
  43.         gTempKeyCodes: array[0..7] of char;    (* Key codes, temporary stoareg while the dialog is open *)
  44.  
  45. (* The following constants must match the DLOG/DITL resource! *)
  46.     const
  47.         kHighDlogRes = 128;
  48.         kOKButton = 1;
  49.         kCancelButton = 2;
  50.         kFirstKey = 3;
  51.         kLastKey = 10;
  52.         kFirstRadio = 11;
  53.         kLastRadio = 13;
  54.         kCheckBox = 14;
  55.         kFirstCode = 15;
  56.         kLastCode = 22;
  57.  
  58.  
  59. (* StdFilter *)
  60.  
  61. (* StdFilter is a dialog filter function that is useful for most}
  62. {modal dialogs, as long as they have an OK and a Cancel button.}
  63. {It maps return and enter to OK, and command-period and ESC to Cancel.}
  64. {It also draws a frame around the OK button. *)
  65.  
  66.     function StdFilter (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer): Boolean;
  67.  
  68.         var
  69.             theChar: char;
  70.             kind: Integer;
  71.             item: Handle;
  72.             box: Rect;
  73.  
  74.     begin
  75.         case theEvent.what of
  76.             keyDown: 
  77.                 begin
  78.                     theChar := char(BAnd(theEvent.message, charCodeMask));
  79.                     if ((BAnd(theEvent.modifiers, cmdKey)) <> 0) and (theChar = '.') or (theChar = char(27)) then (*cmd-. or ESC*)
  80.                         begin
  81.                             itemHit := kCancelButton;
  82. (*Highlight the cancel button*)
  83.                             GetDItem(theDialog, kCancelButton, kind, item, box);
  84.                             HiliteControl(ControlHandle(item), 1);
  85.  
  86.                             StdFilter := true;
  87.                             exit(StdFilter);
  88.                         end;
  89.                     if (theChar = char(13)) or (theChar = char(3)) then
  90.  
  91.                         begin
  92.                             itemHit := kOKButton;
  93. (*Highlight the OK button*)
  94.                             GetDItem(theDialog, 1, kind, item, box);
  95.                             HiliteControl(ControlHandle(item), kOKButton);
  96.  
  97.                             StdFilter := true;
  98.                             exit(StdFilter);
  99.                         end;
  100.                 end; (*keyDown*)
  101.             updateEvt: 
  102.                 begin
  103.                     BeginUpdate(theDialog);
  104.                     SetPort(theDialog);
  105.  
  106.                     DrawDialog(theDialog);
  107.  
  108. (*Frame default button - item 1*)
  109.                     GetDItem(theDialog, kOKButton, kind, item, box);
  110.                     InsetRect(box, -4, -4);
  111.                     PenSize(3, 3);
  112.                     FrameRoundRect(box, 15, 15);
  113.  
  114.                     EndUpdate(theDialog);
  115.                 end; (*update event*)
  116.         end; (*case*)
  117.         StdFilter := false;
  118.     end; (*StdFilter*)
  119.  
  120.  
  121.  
  122.     function KeysFilter (theDialog: DialogPtr; var theEvent: EventRecord; var itemHit: Integer): Boolean;
  123.  
  124.         var
  125.             item: Integer;
  126.             theKeyNumber: Integer;
  127.  
  128.             itemHandle: Handle;
  129.             itemType: Integer;
  130.             itemRect: Rect;
  131.             str: Str255;
  132.     begin
  133.         if BAnd(theEvent.modifiers, cmdKey) <> 0 then            (*Command key held down*)
  134.             KeysFilter := StdFilter(theDialog, theEvent, itemHit)
  135.         else if theEvent.what <> keyDown then                (*Not a keydown*)
  136.             KeysFilter := StdFilter(theDialog, theEvent, itemHit)
  137.         else if BAnd(theEvent.message, charCodeMask) = 3 then (*Enter*)
  138.             KeysFilter := StdFilter(theDialog, theEvent, itemHit)
  139.         else if BAnd(theEvent.message, charCodeMask) = 13 then (*Return*)
  140.             KeysFilter := StdFilter(theDialog, theEvent, itemHit)
  141.         else if BAnd(theEvent.message, charCodeMask) = 27 then (*Escape*)
  142.             KeysFilter := StdFilter(theDialog, theEvent, itemHit)
  143.         else if BAnd(theEvent.message, charCodeMask) = 9 then (*TAB*)
  144.             KeysFilter := StdFilter(theDialog, theEvent, itemHit)
  145.         else
  146. (* Get the key code *)
  147.             begin
  148.                 theKeyNumber := BSR(BAnd(theEvent.message, keyCodeMask), 8);
  149.  
  150.                 if IsDialogEvent(theEvent) then
  151.                     if DialogSelect(theEvent, theDialog, item) then
  152.                         begin
  153.                             itemHit := item;
  154.  
  155. (* If it is one of the key boxes, put the key code in the temprary array *)
  156.                             if (itemHit >= kFirstKey) and (itemHit <= kLastKey) then
  157.                                 begin
  158.                                     gTempKeyCodes[itemHit - kFirstKey] := char(theKeyNumber);
  159.  
  160. (* Just for the demo, I also display the key codes. A real game would never do that. *)
  161.                                     NumToString(theKeyNumber, str);
  162.                                     GetDItem(theDialog, itemHit - kFirstKey + kFirstCode, itemType, itemHandle, itemRect);
  163.                                     SetIText(itemHandle, str);
  164.  
  165.                                     KeysFilter := true;
  166.                                     exit(KeysFilter);
  167.                                 end;
  168.                         end;
  169.             end;
  170.     end; (* KeysFilter*)
  171.  
  172.  
  173. (* AskKeys *)
  174. (* This is the procedure that handles the dialog. *)
  175.  
  176.     function AskKeys (prefs: PrefsHnd): Boolean;
  177.  
  178.         var
  179.             theDialog: DialogPtr;
  180.             oldPort: GrafPtr;
  181.             itemHit: Integer;
  182.             itemHandle: Handle;
  183.             itemType: Integer;
  184.             itemRect: Rect;
  185.             str: Str255;
  186.             itemNo: Integer;
  187.             theFlag: Boolean;
  188.             returnValue: Boolean;
  189.  
  190.     begin
  191.         returnValue := false;
  192.  
  193.         GetPort(oldPort);
  194.         theDialog := GetNewDialog(kHighDlogRes, nil, WindowPtr(-1));
  195.         ShowWindow(theDialog);
  196.         SelectWindow(theDialog);
  197.         SetPort(theDialog);
  198.  
  199. (* Set all dialog items to their initial values *)
  200.  
  201. (* First set all the editable text boxes… *)
  202.         for itemNo := kFirstKey to kLastKey do
  203.             begin
  204.                 GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
  205.                 str[0] := char(1);                                            (* Length 1 *)
  206.                 str[1] := prefs^^.keyChars[itemNo - kFirstKey];    (* Put the char in the string *)
  207.                 SetIText(itemHandle, str);
  208.             end;
  209.  
  210. (* …then the radio buttons… *)
  211.         for itemNo := kFirstRadio to kLastRadio do
  212.             begin
  213.                 GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
  214.                 SetCtlValue(ControlHandle(itemHandle), Integer(itemNo = prefs^^.myRadio));
  215.             end;
  216.  
  217. (* …and the checkbox… *)
  218.         GetDItem(theDialog, kCheckBox, itemType, itemHandle, itemRect);
  219.         SetCtlValue(ControlHandle(itemHandle), Integer(prefs^^.myCheckBox));
  220.  
  221. (* Finally, copy all the key codes to a temporary storage. *)
  222.         for itemNo := 0 to kLastKey - kFirstKey do
  223.             begin
  224.                 gTempKeyCodes[itemNo] := prefs^^.keyCodes[itemNo];
  225.  
  226. (* Just for the demo, I also display the key codes. A real game would never do that. *)
  227.                 NumToString(Longint(prefs^^.keyCodes[itemNo]), str);
  228.                 GetDItem(theDialog, itemNo + kFirstCode, itemType, itemHandle, itemRect);
  229.                 SetIText(itemHandle, str);
  230.             end;
  231.  
  232.  
  233. (* One more thing: let the first key be selected *)
  234.         SelIText(theDialog, kFirstKey, 0, 1);
  235.  
  236.         itemHit := -1;
  237.         while ((itemHit <> 1) and (itemHit <> 2)) do (* 1=ok, 2=cancel *)
  238.             begin
  239.                 ModalDialog(@KeysFilter, itemHit);
  240.  
  241. (* Handle radio buttons and checkboxes here *)
  242.                 if (itemHit = kCheckBox) then
  243.                     begin
  244.                         GetDItem(theDialog, itemHit, itemType, itemHandle, itemRect);
  245.                         theFlag := Boolean(GetCtlValue(ControlHandle(itemHandle)));
  246.                         SetCtlValue(ControlHandle(itemHandle), Integer(not theFlag));
  247.                     end;
  248.  
  249.                 if (itemHit >= kFirstRadio) and (itemHit <= kLastRadio) then
  250.                     for itemNo := kFirstRadio to kLastRadio do
  251.                         begin
  252.                             GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
  253.                             SetCtlValue(ControlHandle(itemHandle), Integer(itemNo = itemHit));
  254.                         end;
  255.  
  256. (* If it was a key, select it *)
  257.                 if (itemHit >= kFirstKey) and (itemHit <= kLastKey) then
  258.                     SelIText(theDialog, itemHit, 0, 32767);
  259.  
  260.             end; (*while*)
  261.  
  262. (* If not cancelled, put the results in the prefs structure. *)
  263.  
  264.         if (itemHit = 1) then
  265.  
  266. (* Get values from the dialog items *)
  267.  
  268. (* First get all the editable text boxes… *)
  269.             begin
  270.                 for itemNo := kFirstKey to kLastKey do
  271.                     begin
  272.                         GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
  273.                         GetIText(itemHandle, str);
  274.                         if (str[0] <> char(0)) then            (* If it's empty, leave it alone. *)
  275.                             prefs^^.keyChars[itemNo - kFirstKey] := str[1];
  276.                     end;
  277.  
  278. (* …then the radio buttons… *)
  279.                 for itemNo := kFirstRadio to kLastRadio do
  280.                     begin
  281.                         GetDItem(theDialog, itemNo, itemType, itemHandle, itemRect);
  282.                         if Boolean(GetCtlValue(ControlHandle(itemHandle))) then
  283.                             prefs^^.myRadio := itemNo;
  284.                     end;
  285.  
  286. (* …and the checkbox… *)
  287.                 GetDItem(theDialog, kCheckBox, itemType, itemHandle, itemRect);
  288.                 prefs^^.myCheckBox := Boolean(GetCtlValue(ControlHandle(itemHandle)));
  289.  
  290. (* Finally, copy all the key codes from the temporary storage. *)
  291.                 for itemNo := 0 to kLastKey - kFirstKey do
  292.                     prefs^^.keyCodes[itemNo] := gTempKeyCodes[itemNo];
  293.  
  294.                 returnValue := true;    (* OK *)
  295.             end;
  296.         ;
  297.         DisposeDialog(theDialog);
  298.         SetPort(oldPort);
  299.         AskKeys := returnValue;
  300.     end; (*AskKeys*)
  301.  
  302.  
  303.  
  304. (*InitPrefs*)
  305. (*This procedure loads the preferences from a resource in the current resource file,*)
  306. (*creating a new one if there is none.*)
  307.  
  308.     procedure InitPrefs;
  309.  
  310.         var
  311.             i: Integer;
  312.             ignoreErr: OSErr;
  313.  
  314.     begin
  315.         gPrefs := PrefsHnd(Get1Resource('Pref', 0));
  316.         if gPrefs = nil then (*Didn't exist - create it!*)
  317.             begin
  318.                 gPrefs := PrefsHnd(NewHandle(sizeof(PrefsRec)));
  319.                 if gPrefs = nil then
  320.                     ExitToShell;                        (*Insert error message here*)
  321.  
  322. (* We should fill it with some values here *)
  323.  
  324.                 AddResource(Handle(gPrefs), 'Pref', 0, 'Preferences');
  325.             end
  326.         else (*Did exist - check the size!*)
  327.             if (GetHandleSize(Handle(gPrefs)) < sizeof(PrefsRec)) then
  328.                 SetHandleSize(Handle(gPrefs), sizeof(PrefsRec));
  329.     end; (*InitScores*)
  330.  
  331.  
  332. (* Standard inits *)
  333.  
  334.     procedure InitToolbox;
  335.     begin
  336. {$ifc UNDEFINED THINK_PASCAL}
  337.         InitGraf(@qd.thePort);
  338.         InitFonts;
  339.         FlushEvents(everyEvent, 0);
  340.         InitWindows;
  341.         InitMenus;
  342.         TEInit;
  343.         InitDialogs(nil);
  344. {$endc}
  345.         InitCursor;
  346.     end;
  347.  
  348. (****************** Main program ******************)
  349.  
  350.  
  351.     var
  352.         str: Str255;
  353.         i: Integer;
  354.         gAppFile, gPrefFile: Integer;
  355.  
  356. begin
  357.     InitToolbox;
  358.  
  359. (*Get the prefs file - create as necessary.*)
  360.     if SetPrefFile('KeyConfig Preferences', '????', 'pref', gAppFile, gPrefFile) then
  361.         ;
  362.  
  363. (*Set the current resource file to the preference file before InitScores*)
  364.     if gPrefFile <> 0 then
  365.         UseResFile(gPrefFile);
  366.     InitPrefs;
  367.     UseResFile(gAppFile);
  368.  
  369.     if AskKeys(gPrefs) then
  370.         begin
  371.             ChangedResource(Handle(gPrefs));
  372.             WriteResource(Handle(gPrefs));
  373.         end;
  374.  
  375.     CloseResFile(gPrefFile);
  376.  
  377. end. (*KeyConfig*)